using System;
using System.IO;
using System.Text;
using System.Collections;
using DesignPatternDefinitions;

namespace CodeGenerators
{
	internal class CPlusPlusClassGenerator : IDPAClassGenerator
	{
		#region Fields
		private IClass objClass = null;
		private IProjectComponent objComponent = null;
		#endregion
		
		#region IDPAClassGenerator Members

		public string GenerateClass(string dirName, DesignPatternDefinitions.IClass objClass, DesignPatternDefinitions.IProjectComponent parent)
		{
			this.objClass = objClass;
			this.objComponent = parent;
			
			string hFilename = dirName + "\\" + objClass.ClassName + ".h";
			string cFilename = dirName + "\\" + objClass.ClassName + ".cpp";

			GenerateHeaderFile(hFilename);
			GenerateClassFile(cFilename);

			return cFilename;
		}

		
		#endregion

		#region Implementation
		private void GenerateHeaderFile(string hFilename)
		{
			StreamWriter writer = new StreamWriter( hFilename );
			TemplateProcessor processor = new TemplateProcessor(
				System.Windows.Forms.Application.StartupPath + Constants.TEMPLATEPATH + "\\Template.h"
			);
			processor["ClassName"] = objClass.ClassName;
			processor["Namespace"] = objComponent.ComponentName;
			processor["ClassSummary"] = objClass.ClassSummary;
			processor["ForwardDeclarations"] = GetForwardDeclarations();
			processor["Specifiers"] = objClass.GetMetaInfo(Constants.CPP);
			processor["BaseClasses"] = GetBaseClasses();
			processor["Aggregates"] = GetAggregates();
			processor["References"] = GetReferences();
			processor["Creates"] = GetCreates();
			processor["Fields"] = GetFields();
			processor["Methods"] = GetMethods();
			writer.WriteLine(
				processor.Render()
			);
			writer.Close();
		}
		private void GenerateClassFile(string cFilename)
		{
			StreamWriter writer = new StreamWriter( cFilename );
			TemplateProcessor processor = new TemplateProcessor(
				System.Windows.Forms.Application.StartupPath + Constants.TEMPLATEPATH + "\\Template.cpp"
			);
			processor["ClassName"] = objClass.ClassName;
			processor["Namespace"] = objComponent.ComponentName;
			processor["Methods"] = GetMethodBodies();
			writer.WriteLine(
				processor.Render()
			);
			writer.Close();
		}
		private string GetForwardDeclarations()
		{
			string indentString = "\t";
			StringBuilder builder = new StringBuilder();
			ArrayList inhList = objClass.InheritedClasses;
			foreach(IInheritance i in inhList) 
				builder.AppendFormat("\n"+indentString+"class {0};\r\n",i.BaseClass);
			return builder.ToString();
		}
		private string GetBaseClasses()
		{
			StringBuilder builder = new StringBuilder();
			bool first = true;
			int inhcount = 0;
			ArrayList inhList = objClass.InheritedClasses;
			foreach(IInheritance inh in inhList)
			{
				if(first) 
				{
					builder.Append( ":" );
					first = false;
				}
				inhcount ++;
				builder.AppendFormat("public {0} ",inh.BaseClass);
				if(inhList.Count - inhcount > 0)
					builder.Append(", ");
			}
			return builder.ToString();
		}
		private string GetAggregates()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList AggregatesList = objClass.Aggregates;
			foreach(IAggregate agg in AggregatesList) 
			{
				string aggFldName = agg.AggregateName;
				if(aggFldName!=null && aggFldName==string.Empty)
					aggFldName = "noNameAggField"+AggregatesList.IndexOf(agg);
				string order = agg.Order.ToString();
				if (order == "Single")
					builder.AppendFormat("{0} {1};\r\n",agg.AggregateeClass,aggFldName);
				if (order == "Multiple")
					builder.AppendFormat("list<{0}> {1};\r\n",agg.AggregateeClass,aggFldName);
			}
			return builder.ToString();
		}
		private string GetReferences()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList ReferencesList = objClass.References;
			if(ReferencesList.Count > 0)
				foreach(IReference ir in ReferencesList) 
					builder.AppendFormat("{0} in {1} \r\n",ir.ReferedClassName,ir.ReferenceComponent);
			return builder.ToString();
		}
		private string GetCreates()
		{
			StringBuilder builder = new StringBuilder();
			ArrayList CreatesList = objClass.Creations;
			if(CreatesList.Count>0)
				foreach(ICreation ic in CreatesList) 
					builder.AppendFormat(" {0} in {1} \r\n",ic.CreateeClassName,ic.CreateeComponentName);
			return builder.ToString();
		}
		private string GetFields()
		{
			string indentString = "\t\t";
			string fldIndentStr = "\t\t\t";
			StringBuilder builder = new StringBuilder();
			string currVisibility = "";
			ArrayList FieldsList = objClass.Fields;
			foreach(IField field in FieldsList) 
			{
				if(currVisibility != field.FieldVisibility) 
				{
					builder.AppendFormat("\n"+indentString+"{0}:\r\n",field.FieldVisibility);
					currVisibility = field.FieldVisibility;
				}
				builder.AppendFormat(fldIndentStr + "/** {0} */\r\n", field.FieldSummary );
				builder.AppendFormat(
					fldIndentStr+"{0} {1} {2};\r\n",
					field.GetMetaInfo(Constants.CPP),
					field.FieldType,
					field.FieldName
				);
			}
			return builder.ToString();
		}
		private string GetMethods()
		{
			string indentString = "\t\t";
			string methodIndentStr = "\t\t\t";
			StringBuilder builder = new StringBuilder();
			ArrayList MethodsList =  objClass.Methods;
			string currVisibility = "";
			
			
			foreach(IMethod method in MethodsList) 
			{
				if(currVisibility != method.MethodVisibility) 
				{
					builder.AppendFormat("\n"+indentString+"{0}:\r\n",method.MethodVisibility);
					currVisibility = method.MethodVisibility;
				}

				builder.AppendFormat(methodIndentStr+"/** {0} */\r\n",method.MethodSummary);
				
					builder.AppendFormat(
						methodIndentStr+"{0} {1} {2} (",
						method.GetMetaInfo(Constants.CPP),
						method.MethodReturnType,
						method.MethodName
					);
				ArrayList ParametersList = method.Parameters;
				int cpIndex = 0;
				foreach(IParameter parameter in ParametersList) 
				{
					builder.AppendFormat(
						"{0} {1} {2}",
						parameter.GetMetaInfo(Constants.CPP),
						parameter.ParameterType,
						parameter.ParameterName
					);
					++cpIndex;
					if ( ParametersList.Count - cpIndex > 0)
						builder.Append(", ");
				}
				builder.Append(") ;\n");
			}
			return builder.ToString();
		}
		private string GetMethodBodies()
		{
			string indentString = "\t";
			StringBuilder builder = new StringBuilder();
			ArrayList MethodsList = objClass.Methods;

			foreach(IMethod method in MethodsList)
			{
				if(method.MethodType == MethodType.Abstract)
					continue;
				builder.AppendFormat( 
					"\n"+indentString+"{0} {1}::{2}( " ,
					method.MethodReturnType,
					objClass.ClassName,
					method.MethodName
				);
				ArrayList ParametersList = method.Parameters;
				int cpIndex = 0;
				foreach(IParameter parameter in ParametersList) 
				{
					builder.AppendFormat(
						"{0} {1} {2}",
						parameter.GetMetaInfo(Constants.CPP),
						parameter.ParameterType,
						parameter.ParameterName
					);
					++cpIndex;
					if ( ParametersList.Count - cpIndex > 0)
						builder.Append(", ");
				}
				builder.Append("){\r\n"+indentString +"}\n");
			}
			return builder.ToString();
		}
		#endregion
	}
}
